【axios】你的进度条准确吗 您所在的位置:网站首页 vue接口调用axios 精度 【axios】你的进度条准确吗

【axios】你的进度条准确吗

2024-03-22 00:51| 来源: 网络整理| 查看: 265

1、axios监听进度

上传和下载操作在前端中是非常常见的,当我们想知道上传或下载的进度时也不难,axios已经实现了监听进度的方法

import axios from 'axios' // 上传请求 axios.post('/api/v1/upload', { data: xxx }, { // onUploadProgress回调可以获取进度 onUploadProgress(e) { const complete = e.loaded / e.total * 100 } } ) // 或者 axios({ method: 'POST', data: { data: xxx }, onUploadProgress(e) { const complete = e.loaded / e.total * 100 } })

翻一下axios的源码,看看它是如何实现的

在/lib/adapters/xhr.js文件中,可以看到这么一段代码

let request = new XMLHttpRequest() // Not all browsers support upload events if (typeof config.onUploadProgress === 'function' && request.upload) { request.upload.addEventListener('progress', progressEventReducer(config.onUploadProgress)); }

axios是基于XMLHttpRequest来实现的

其中,config就是我们传给的axios的参数,如果是上传操作并且有传递onUploadProgress函数的话

就监听XMLHttpRequest的progress事件,然后周期性地触发回调函数progressEventReducer

再看一下progressEventReducer的实现:

function progressEventReducer(listener, isDownloadStream) { return e => { const loaded = e.loaded; const total = e.lengthComputable ? e.total : undefined; ... const data = { loaded, total, progress: total ? (loaded / total) : undefined, ... }; data[isDownloadStream ? 'download' : 'upload'] = true; // 区别上传或是下载 listener(data); }; }

在progressEventReducer中,就会获取

loaded:已上传的buffer数据流 total:总的buffer数据流

最终会将数据传给listener,即一开始传给axios的onUploadProgress回调,所以我们可以通过e.loaded / e.total来获取进度

2、不准确的进度条

获取进度条很简单,但是在实际使用中还是碰到了问题

计算出来的进度与实际上传进度不符合

可以看出:进度条已经走完,但是接口一直在pending中

这个问题还是比较严重的,明明显示完成了上传,但是文件就是没有出来

而且文件越大,差异就越明显

原因

造成这个原因,其实跟TCP协议发送数据的方式有关

在客户端,会有一个send buffer,即数据缓存区 这个buffer缓存区存储的就是等待发送的数据,tcp协议层会在适当的时候选取一部分数据发送出去 当我们上传文件时,数据会被不断地write到这个缓存区;每次写入时 就会被侦听到,然后调用一次onUploadProgress,e.loaded其实表示的就是写入到buffer缓存区的数据 但是此时的数据可能还没有被发送出去,仍然在缓存区中放着;加上发送数据也需要时间 等到数据全部到达Server的时候,才会执行response回调,这时候上传操作才算完成;但客户端那边早就显示发送完毕了,时差也就出来了

3、模拟进度条

如果解决这个问题呢?有一个比较保守的做法:用一个亦真亦假的进度条

在进度达到一定值的时候,开始人为干涉;每次让它走一点,给人一种一直在上传的感觉,直到上传完成,赋值为100即可

这里就使用vue3的方式实现一下:

import { ref } from 'vue' /** * 模拟进度条 * @returns */ export const useProgress = (name: string) => { const progress = ref(0) const timer = ref(null) const onUploadProgress = (e: ProgressEvent) => { const complete = (e.loaded / e.total) * 100 // 超过80 开始干涉 if (complete >= 80) { if (timer.value) return timer.value = window.setInterval(() => { progress.value += (100 - progress.value) * 0.2 // 每次增加剩下的20% // 超过99 不再变化(此时也接近上传完成了) if (progress.value > 99) { timer.value && window.clearInterval(timer.value) }, 1000) } else { // 在80之前都按照axios计算出的进度来显示 progress.value = complete } } return { progress, onUploadProgress } } 可以在请求完成的时候,将progress设置为100即可 具体的阈值可以根据情况自行设置

其实,大名鼎鼎的NProgress库也是这么做的,我们平时使用它的姿势是这样的:

NProgress.start() // 开启进度条 NProgress.done() // 进度条结束

可是,又没有监听接口,仅仅只是开启进度条,它怎么能预测我们的进度呢?

答案是:它也是模拟进度条

在其源码中,有这么一段代码:

当我们没有传amount的时候,会自动根据当前进度条的status调整每次的进度amount 当进度staus超过0.994的时候,就会一直停在0.994这个状态 直到我们执行NProgress.done()时,会直接调用NProgress.set(1),进度条走完

参考:

github.com/axios/axios github.com/rstacruz/np…


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有